`timescale 1ns / 1ns
`include "../include/cpu_defines.sv"
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/04/29 01:59:58
// Design Name: 
// Module Name: branch_predict
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module BranchPredict #(
	parameter INST_BUFFER_SIZE=16,
	parameter INDEX_SIZE=7,
	parameter TAG_SIZE=9,
	parameter COUNTER_SIZE=3,
	parameter USE_SIZE=2
)(
    input logic cpu_clk,
	input logic cpu_rst_n,
	input logic clear,
	input logic stall,
	input logic instBuffer_ok,
	input logic inst_accept,
    input logic[31:0] pc,
    input logic[31:0] next_pc,//不跳转的话，下一条指令的地址
	input logic next_inst1_en,
	input logic next_inst2_en,
	input logic [31: 0] next_inst1,
	input logic [31: 0] next_inst2,
	input logic [31: 0] next_addr1,
	input logic [31: 0] next_addr2,
	input logic [2: 0] next_index1,
	input logic [2: 0] next_index2,
	input logic retire_en1,
	input logic retire_en2,
	input logic branch_fail1,
	input logic branch_fail2,
	input logic ras_up1,
	input logic ras_up2,
	input logic ras_down1,
	input logic ras_down2,
	input logic dis_en1,
	input logic dis_en2,
	input logic wb_en1,
	input logic wb_en2,
	input logic [3: 0] wb_branch_index1,
	input logic [3: 0] wb_branch_index2,
	input logic [31: 0]wb_branch1,
	input logic [31: 0]wb_branch2,
	input logic delay_accept,
	output logic [$clog2(INST_BUFFER_SIZE)-1: 0] dis_branch_index,
    output logic predict_conflict1,//是否发生分支预测错误
	output logic predict_conflict2,
	output logic is_fail,
	output logic [31: 0] fail_addr,
	output logic [31: 0] branch_addr,
	output logic predict_clear,
	// output logic inst2_selector,
	output logic front_clear, // 下一次将要跳转，将清空inst_buffer且重置icache
	output logic inst_buffer_full,
	output logic discard_inst2,
	input logic ds_en,
	output logic [2: 0] ds_index,
	output logic delay_clear,
	output logic [2: 0] delay_index,
	output logic [2: 0] clear_index,
	output logic reject_inst,
	output logic reject_inst2,
	output logic clear_discard1,
	output logic clear_discard2
	// output logic if_exccode,
	// output logic [31: 0] branch_exc_addr, // j jal
	// output logic [`EXC_CODE_BUS] wb_branch_exception1,
	// output logic [`EXC_CODE_BUS] wb_branch_exception2,
	// output logic [31: 0] retire_branch_exc_addr // other type of branch inst
    );

    // 用来保存分支指令的缓�?????
    typedef struct packed{
		logic en;
		logic _type;
		logic index_ready;
		logic btb_delay;
		logic branch;
		// logic uncorrect_branch;	
		logic provider_branch;
		logic alt_branch;
		logic real_branch;
		// logic ght_branch;
		logic [4: 0][INDEX_SIZE-1: 0] index;
		logic [3: 0][TAG_SIZE-1: 0] tag;
		logic [INDEX_SIZE-1: 0] ght_index;
		logic [5: 0] btb_index;
		logic [3: 0] provider;
		logic [29: 0] btb_tag;
		logic [31: 0] real_addr;
        logic[31:0] predict_addr;
		logic [31: 0] normal_addr;
		logic predict_exc;
    } inst_info;
    inst_info inst_buffer[INST_BUFFER_SIZE-1: 0];
	inst_info buffer_tail_data, store_info;
	logic [$clog2(INST_BUFFER_SIZE)-1: 0] buffer_head, buffer_tail, buffer_headp1, buffer_tailp1, retire_tailp1;
	logic [$clog2(INST_BUFFER_SIZE)-1: 0] rob_tail, rob_tailp1;
	logic [$clog2(INST_BUFFER_SIZE)-1: 0] head_index;
	logic [$clog2(INST_BUFFER_SIZE): 0] buffer_remain_count;
	logic wb_hit1, wb_hit2;
	logic [1: 0] add_num, sub_num;
	logic inst1_store, inst2_store;
	logic next_predict_clear;
	logic front_clear_accept, front_clear_availiable;
	logic inst1_en, inst2_en, inst2_en_in, next_front_clear;
	logic inst1_analyze_store, inst2_analyze_store;
	logic [2: 0] inst_buffer_index1, inst_buffer_index2;
	// logic inst1_branch, inst2_branch;
	// logic inst1_jump, inst2_jump;

	logic [31: 0] inst1_addr4, inst2_addr4, inst1_addr8, inst2_addr8;
	logic [29: 0] pc4;
	logic [31: 0] predict_addr1, predict_addr2;
    logic[1:0] analyze_result1,analyze_result2;
    logic[31:0] analyze_addr1,analyze_addr2, inst1, inst2;
	logic [31: 0] inst1_addr, inst2_addr;
	logic inst1_choose;
	logic inst1_multdiv, inst2_multdiv;
	logic inst1_need_jump, inst2_need_jump, next_inst1_need_jump, next_inst2_need_jump;
	logic [31: 0] next_addr1_store, next_addr2_store;
	logic delay_branch;
	logic [1: 0] delay_analyze_result;
	logic [31: 0] delay_addr, delay_addr_predict, delay_addr_normal, predict_addr, real_addr1;

	logic [3: 0] alt_ctr, ght_ctr;
	logic [4: 0] predictions, pre_predictions;
	logic prediction, predict_branch, alt_predict_branch;
	logic update_use;
	logic [3: 0] providers;
	logic [INDEX_SIZE-1: 0] hash_indexs[3: 0];
	logic [TAG_SIZE-1: 0] hash_tags[3: 0];
	logic [INDEX_SIZE-1: 0] next_hash_indexs[3: 0];
	logic [TAG_SIZE-1: 0] next_hash_tags[3: 0];
	logic [3: 0] tag_hits, alt_tag_hits, pre_tag_hits;
	logic [3: 0] dec_uses;
	logic [3: 0] u;
	logic [3: 0] allocs;
	logic [3: 0] new_entrys;
	logic [5: 0] correct_ctr;
	logic predict_result, delay_result;
	logic uncorrect_branch;
	logic correct;
	logic new_entry;
	logic update_en;
	logic ght_branch;
	logic [129: 0] ghr, retire_ghr;
	logic [31: 0] target_addr, next_target_addr, clear_accept_addr;
	logic [INDEX_SIZE-1: 0] hash_addr, next_hash_index1, next_hash_index2, next_hash_index3, next_hash_index4;
	logic [INDEX_SIZE-1: 0] next_tag_index1, next_tag_index2, next_tag_index3, next_tag_index4;
	logic revert;
	logic [7: 0] random;
	logic [3: 0] random_u;
	// logic [$clog2(INST_BUFFER_SIZE)-1: 0] wb_hit_index1, wb_hit_index2;

	logic ras_inst1_we, ras_inst2_we, ras_inst1_re, ras_inst2_re;
	logic ras_we, ras_re;
	logic [31: 0] ras_addr;

	logic btb_en, accept_btb, inst_btb;
	logic btb_delay, accept_btb_delay, inst_btb_delay;
	logic [5: 0] btb_index1;
	logic [5: 0] btb_index2;
	logic [31: 0] btb_addr;

	assign inst1_choose = inst1_en && analyze_result1 != 2'b00;
	assign inst1_addr4 = inst1_addr + 4;
	assign inst2_addr4 = inst2_addr + 4;
	assign pc4 = pc[31: 2] + 1;
	assign inst1_addr8 = inst1_addr + 8;
	assign inst2_addr8 = inst2_addr + 8;

	assign buffer_tailp1 = buffer_tail + 1;
	assign retire_tailp1 = retire_en1 ? buffer_tailp1 : buffer_tail;
	assign buffer_headp1 = buffer_head + 1;
	assign rob_tailp1 = rob_tail + 1;
	assign head_index = buffer_head;
	assign ds_index = inst1_en && analyze_result1 != 2'b00 ? inst_buffer_index1 + 1 : inst_buffer_index2 + 1;

	assign inst1_store = inst1_en && (analyze_result1 == 2'b01 || analyze_result1 == 2'b11) && !front_clear_accept;
	assign inst2_store = inst2_en && (analyze_result2 == 2'b01 || analyze_result2 == 2'b11) && !front_clear_accept;

	assign add_num[1] = inst1_store & inst2_store;
	assign add_num[0] = inst1_store ^ inst2_store;
	assign sub_num[1] = retire_en1 & retire_en2;
	assign sub_num[0] = retire_en1 ^ retire_en2;
	assign inst_buffer_full = buffer_remain_count <= 3 || (!next_front_clear & front_clear_accept);
	assign buffer_tail_data = inst_buffer[buffer_tail];
	assign predict_result = inst1_en & inst2_en & (analyze_result1[1] & analyze_result1[0] | analyze_result1[1] & ~analyze_result1[0] & ~inst_btb | ~analyze_result1[1] & analyze_result1[0] & (predict_branch ^ inst_btb));
	assign delay_result = delay_accept & (delay_analyze_result[1] & delay_analyze_result[0] | delay_analyze_result[1] & ~delay_analyze_result[0] & ~inst_btb | ~delay_analyze_result[1] & delay_analyze_result[0] & (delay_branch ^ inst_btb));

	localparam T0 = 4'b0000;
    localparam T1 = 4'b0001;
    localparam T2 = 4'b0010;
    localparam T3 = 4'b0100;
    localparam T4 = 4'b1000;

	for(genvar i=0; i<4; i++)begin
		TageTable #(
			.INDEX_SIZE(INDEX_SIZE),
			.TAG_SIZE(TAG_SIZE),
			.COUNTER_SIZE(COUNTER_SIZE),
			.USE_SIZE(USE_SIZE)
		) tage_table(
			.cpu_clk(cpu_clk),
			.cpu_rst_n(cpu_rst_n),
			.real_branch(buffer_tail_data.real_branch),
			.update_en(update_en),
			.provider(buffer_tail_data.provider[i]),
			.alloc(allocs[i]),
			.update_use(update_use),
			.dec_use(dec_uses[i]),
			.update_index(buffer_tail_data.index[i+1]),
			.search_index(hash_indexs[i]),
			.search_tag(hash_tags[i]),
			.update_tag(buffer_tail_data.tag[i]),
			.new_entry(new_entrys[i]),
			.prediction(predictions[i+1]),
			.tag_hit(tag_hits[i]),
			.out_u(u[i])
		);
	end

	BHT #(.INDEX_SIZE(INDEX_SIZE)) bht(
		.cpu_clk(cpu_clk),
		.update_en(update_en && buffer_tail_data.provider == 4'b0),
		.real_branch(buffer_tail_data.real_branch),
		.search_index(target_addr[INDEX_SIZE+1: 2]),
		.update_index(buffer_tail_data.index[0]),
		.prediction(predictions[0])
	);

	assign ras_we = inst1_en & ras_inst1_we | inst2_en & ras_inst2_we;
	assign ras_re = inst1_en & ras_inst1_re | inst2_en & ras_inst2_re;
	RAS ras(
		.cpu_clk(cpu_clk),
		.cpu_rst_n(cpu_rst_n),
		.clear(predict_clear || clear),
		.ras_up1(ras_up1),
		.ras_up2(ras_up2),
		.ras_down1(ras_down1),
		.ras_down2(ras_down2),
		.we(ras_we),
		.re(ras_re),
		.addr(ras_inst1_we ? inst1_addr8 : inst2_addr8),
		.out_addr(ras_addr)
	);

	assign btb_index1 = pc[8: 3] ^ pc[14: 9] ^ pc[20: 15] ^ pc[26: 21];
	assign btb_index2 = pc4[6: 1] ^ pc4[12: 7] ^ pc4[18: 13] ^ pc4[24: 19];
	logic btb_jstore; // record j and jal
	logic next_btb_jdelay;
	logic retire_btb_en;
	logic [31: 0] next_btb_jaddr;
	logic [29: 0] next_btb_jtag;
	logic [5: 0] next_btb_jindex;
	always_ff @(posedge cpu_clk)begin
		btb_jstore <= retire_btb_en | (inst1_en & analyze_result1[1] & ~analyze_result1[0] | inst2_en & analyze_result2[1] & ~analyze_result2[0]);
		next_btb_jaddr <= retire_btb_en ? buffer_tail_data.predict_addr : inst1_en & analyze_result1[1] & ~analyze_result1[0] ? analyze_addr1 : analyze_addr2;
		next_btb_jtag <= retire_btb_en ? buffer_tail_data.btb_tag : inst1_en & analyze_result1[1] & ~analyze_result1[0] ? inst1_addr4[31: 2] : inst2_addr4[31: 2];
		next_btb_jindex <= retire_btb_en ? buffer_tail_data.btb_index : inst1_en & analyze_result1[1] & ~analyze_result1[0] ? inst1_addr4[8: 3] ^ inst1_addr4[14: 9] ^ inst1_addr4[20: 15] ^ inst1_addr4[26: 21] : inst2_addr4[8: 3] ^ inst2_addr4[14: 9] ^ inst2_addr4[20: 15] ^ inst2_addr4[26: 21];
		next_btb_jdelay <= retire_btb_en ? buffer_tail_data.btb_delay : inst1_en & analyze_result1[1] & ~analyze_result1[0] ? inst1_addr[2] : inst2_addr[2];
	end
	assign retire_btb_en = (retire_en1 | retire_en2) & ~buffer_tail_data._type;
	Btb btb(
		.cpu_clk(cpu_clk),
		.cpu_rst_n(cpu_rst_n),
		.search_index1(btb_index1),
		.search_index2(btb_index2),
		.search2_unvalid((pc[4] & pc[3] & pc[2])),
		.search_tag1(pc[31: 2]),
		.search_tag2(pc4),
		.update_en((btb_jstore)),
		.real_branch(btb_jstore),
		.update_index(next_btb_jindex),
		.update_delay(next_btb_jdelay),
		.update_tag(next_btb_jtag),
		.update_addr(next_btb_jaddr),
		.out_en(btb_en),
		.out_delay(btb_delay),
		.out_addr(btb_addr)
	);

	assign update_en = (retire_en1 | retire_en2) & ~buffer_tail_data._type;
	assign next_target_addr = next_inst1_en & inst1_need_jump ? next_addr1 : next_addr2;
	// assign target_addr =  next_inst1_need_jump ? next_addr1_store : next_addr2_store;
	assign inst2_en = inst2_en_in & ~delay_result;
	assign discard_inst2 = delay_accept & (delay_analyze_result[1] & delay_analyze_result[0] | delay_analyze_result[1] & ~delay_analyze_result[0] & ~inst_btb | ~delay_analyze_result[1] & delay_analyze_result[0] & delay_branch & ~inst_btb);
	assign dis_branch_index = rob_tail;
	assign next_hash_indexs[0] = next_target_addr[6:0]^next_target_addr[13:7]^next_target_addr[20:14]^next_target_addr[28:21]  ^ next_hash_index1;
	assign next_hash_indexs[1] = next_target_addr[6:0]^next_target_addr[13:7]^next_target_addr[20:14]^next_target_addr[28:21]  ^ next_hash_index2;
	assign next_hash_indexs[2] = next_target_addr[6:0]^next_target_addr[13:7]^next_target_addr[20:14]^next_target_addr[28:21]  ^ next_hash_index3;
	assign next_hash_indexs[3] = next_target_addr[6:0]^next_target_addr[13:7]^next_target_addr[20:14]^next_target_addr[28:21]  ^ next_hash_index4;
	assign next_hash_tags[0] = target_addr[8:0]^next_tag_index1;
	assign next_hash_tags[1] = target_addr[8:0]^next_tag_index2;
	assign next_hash_tags[2] = target_addr[8:0]^next_tag_index3;
	assign next_hash_tags[3] = target_addr[8:0]^next_tag_index4;
	always_ff @(posedge cpu_clk)begin
		inst1_addr <= next_addr1;
		inst2_addr <= next_addr2;
		inst1 <= next_inst1;
		inst2 <= next_inst2;
		target_addr <= next_target_addr;
		next_front_clear <= front_clear;
		next_predict_clear <= predict_clear;
		next_inst1_need_jump <= inst1_need_jump;
		// predictions <= pre_predictions;
		// next_addr1_store <= next_addr1;
		// next_addr2_store <= next_addr2;
		// next_hash_index1 <= {2'b0, ghr[4:0]};
		// next_hash_index2 <= ghr[6:0]^ghr[13: 7];
		// next_hash_index3 <= ghr[6:0]^ghr[13: 7]^ghr[20:14]^ghr[27:21]^ghr[34:28]^ghr[41:35]^{4'b0, ghr[44:42]};
		// next_hash_index4 <= ghr[6:0]^ghr[13: 7]^ghr[20:14]^ghr[27:21]^ghr[34:28]^ghr[41:35]^ghr[48:42]^ghr[55:49]^ghr[62:56]^ghr[69:63]^ghr[76:70]^ghr[83:77]^ghr[90:84]^ghr[97:91]^ghr[104:98]^ghr[111:105]^ghr[118:112]^ghr[125:119]^{3'b0, ghr[129:126]};
		next_hash_index1 <= ghr[6: 0];
		next_hash_index2 <= ghr[6: 0] ^ ghr[13: 7];
		next_hash_index3 <= ghr[6: 0] ^ ghr[13: 7] ^ ghr[20: 14] ^ ghr[27: 21] ^ ghr[34: 28] ^ ghr[41: 35] ^ ghr[48: 42];
		next_hash_index4 <= ghr[6: 0] ^ ghr[13: 7] ^ ghr[20: 14] ^ ghr[27: 21] ^ ghr[34: 28] ^ ghr[41: 35] ^ ghr[48: 42] ^ ghr[55: 49] ^ ghr[63: 56] ^ ghr[69: 63] ^ ghr[76: 70] ^ ghr[83: 77] ^ ghr[90: 84] ^ ghr[97: 91] ^ ghr[104: 98] ^ ghr[111: 105] ^ ghr[118: 116] ^ ghr[125: 119];
		// next_hash_index1 <= {3'b0, ghr[4: 0]};
		// next_hash_index2 <= ghr[7: 0] ^ {1'b0, ghr[14: 8]};
		// next_hash_index3 <= ghr[7: 0] ^ ghr[15: 8] ^ ghr[23: 16] ^ ghr[31: 24] ^ ghr[39: 32] ^ {3'b0, ghr[44: 40]};
		// next_hash_index4 <= ghr[7: 0] ^ ghr[15: 8] ^ ghr[23: 16] ^ ghr[31: 24] ^ ghr[39: 32] ^ ghr[47: 40] ^ ghr[55: 48] ^ ghr[63: 56] ^ ghr[71: 64] ^ ghr[79: 72] ^ ghr[87: 80] ^ ghr[95: 88] ^ ghr[103: 96] ^ ghr[111: 104] ^ ghr[119: 112] ^ ghr[127: 120];
		next_tag_index1 <= {4'b0, ghr[4:0]}^{3'b0, ghr[4:0], 1'b0};
		next_tag_index2 <= ghr[8:0]^{3'b0, ghr[14:9]}^{ghr[7:0], 1'b0}^{1'b0, ghr[14:8], 1'b0};
		next_tag_index3 <= ghr[8:0]^ghr[17:9]^ghr[26:18]^ghr[35:27]^{1'b0, ghr[43:36]}^{ghr[7:0], 1'b0}^{ghr[15:8], 1'b0}^{ghr[23:16], 1'b0}^{ghr[31:24], 1'b0}^{ghr[39:32], 1'b0}^{4'b0 ,ghr[43:40], 1'b0};
		next_tag_index4 <= ghr[8:0]^ghr[17:9]^ghr[26:18]^ghr[35:27]^{1'b0, ghr[43:36]}^{ghr[7:0], 1'b0}^{ghr[15:8], 1'b0}^{ghr[23:16], 1'b0}^{ghr[31:24], 1'b0}^{ghr[39:32], 1'b0}^{ghr[47:40], 1'b0}^{ghr[55:48], 1'b0}^{ghr[63:56], 1'b0}^{ghr[71:64], 1'b0}^{ghr[79:72], 1'b0}^{ghr[87:80], 1'b0}^{ghr[95:88], 1'b0}^{ghr[103:96], 1'b0}^{ghr[111:104], 1'b0}^{ghr[119:112], 1'b0}^{ghr[127:120], 1'b0}^{6'b0 ,ghr[129:128], 1'b0};
		inst1_en <= next_inst1_en & ~front_clear_accept & ~clear ;
		inst2_en_in <= next_inst2_en & ~front_clear_accept & ~clear & ~accept_btb_delay;

		hash_indexs[0] <=next_hash_indexs[0];
		hash_indexs[1] <=next_hash_indexs[1];
		hash_indexs[2] <=next_hash_indexs[2];
		hash_indexs[3] <=next_hash_indexs[3];

		hash_tags[0] <= next_hash_tags[0];
		hash_tags[1] <= next_hash_tags[1];
		hash_tags[2] <= next_hash_tags[2];
		hash_tags[3] <= next_hash_tags[3];
	end
//	assign target_addr = inst1_choose ? inst1_addr : inst2_addr;
	// assign hash_indexs[0] =next_hash_index1;
	// assign hash_indexs[1] =next_hash_index2;
	// assign hash_indexs[2] =next_hash_index3;
	// assign hash_indexs[3] =next_hash_index4;

	// assign hash_tags[0] = target_addr[8:0]^next_tag_index1;
	// assign hash_tags[1] = target_addr[8:0]^next_tag_index2;
	// assign hash_tags[2] = target_addr[8:0]^next_tag_index3;
	// assign hash_tags[3] = target_addr[8:0]^next_tag_index4;

	assign providers = tag_hits[3] ? T4 : tag_hits[3] ? T3 : tag_hits[2] ? T2 : tag_hits[1] ? T1 : T0;
    assign prediction = tag_hits[3] ? predictions[4] :
                tag_hits[2] ? predictions[3] :
                tag_hits[1] ? predictions[2] :
                tag_hits[0] ? predictions[1] : predictions[0];
	assign alt_tag_hits = providers ^ tag_hits;
    // assign alt_providers = alt_tag_hits[3] ? 4'b1000 :
    //                     alt_tag_hits[2] ? 4'b0100 :
    //                     alt_tag_hits[1] ? 4'b0010 :
    //                     alt_tag_hits[0] ? 4'b0001 : 4'b0;
	assign alt_predict_branch = alt_tag_hits[2] ? predictions[3] : 
								alt_tag_hits[1] ? predictions[2] :
								alt_tag_hits[0] ? predictions[1] : predictions[0];
	// assign alt_predict_branch = (alt_providers & predictions) != 0;
	assign new_entry = new_entrys & providers;
	assign revert = (correct_ctr[5] | correct_ctr[4] | correct_ctr[3]) & ~(|tag_hits);
	always_comb begin
		if(~new_entry || !(alt_ctr[3]))begin
			predict_branch = prediction;
		end
		else begin
			predict_branch = alt_predict_branch;
		end
	end
	// assign predict_branch = revert ? ~uncorrect_branch : uncorrect_branch;


	assign predict_addr1 = inst1_en & (~analyze_result1[1] & analyze_result1[0]) & ~predict_branch ? inst1_addr8 : analyze_addr1;
	assign predict_addr2 = inst2_en & (~analyze_result2[1] & analyze_result2[0]) & ~predict_branch ? inst2_addr8 :  analyze_addr2;
	assign predict_addr = predict_result & ~clear & ~next_front_clear ? predict_addr1 : btb_en ? btb_addr : next_pc;
	assign branch_addr = front_clear_accept & instBuffer_ok & ~next_front_clear & ~clear ? clear_accept_addr : delay_result & ~next_front_clear & ~clear ? delay_addr : predict_addr;
	assign fail_addr = real_addr1;
	assign is_fail = (retire_en1 | retire_en2) & (branch_fail1 | branch_fail2);
	assign predict_clear = (branch_fail1 || branch_fail2);
	assign front_clear_availiable = !front_clear_accept && !clear && (predict_result | delay_result);
	assign front_clear = (front_clear_accept & ~next_front_clear & ~clear | front_clear_availiable) & instBuffer_ok;
	assign reject_inst = front_clear_accept | ~front_clear_accept & (delay_result | predict_result);
	assign reject_inst2 = accept_btb_delay ;

	assign real_addr1 = buffer_tail_data._type ? buffer_tail_data.real_addr : buffer_tail_data.real_branch ? buffer_tail_data.predict_addr : buffer_tail_data.normal_addr;

	assign wb_hit1 = wb_en1 && inst_buffer[wb_branch_index1].en && inst_buffer[wb_branch_index1].index_ready;
	assign wb_hit2 = wb_en2 && inst_buffer[wb_branch_index2].en && inst_buffer[wb_branch_index2].index_ready;

	assign predict_conflict1 = (wb_hit1) & (inst_buffer[wb_branch_index1].branch != wb_branch1[0] && !inst_buffer[wb_branch_index1]._type || inst_buffer[wb_branch_index1]._type && inst_buffer[wb_branch_index1].predict_addr != wb_branch1); 
	assign predict_conflict2 = (wb_hit2) & (inst_buffer[wb_branch_index2].branch != wb_branch2[0] && !inst_buffer[wb_branch_index2]._type || inst_buffer[wb_branch_index2]._type && inst_buffer[wb_branch_index2].predict_addr != wb_branch2); 

    // 用来处理输入的inst1，判断是不是分支指令
    inst_analyze inst_analyze1(
		.cpu_clk(cpu_clk),
		.cpu_rst_n(cpu_rst_n),
		.inst_en(inst1_en),
		.pre_inst(next_inst1),
		.pre_pc(next_addr1),
        .analyze_result(analyze_result1),
        .analyze_addr(analyze_addr1),
		.branch(inst1_need_jump),
		.store(inst1_analyze_store),
		.ras_we(ras_inst1_we),
		.ras_re(ras_inst1_re),
		.ras_addr(ras_addr)
    );
    inst_analyze inst_analyze2(
		.cpu_clk(cpu_clk),
		.cpu_rst_n(cpu_rst_n),
		.pre_inst(next_inst2),
		.pre_pc(next_addr2),
        .inst_en(inst2_en),
        .analyze_result(analyze_result2),
        .analyze_addr(analyze_addr2),
		.branch(inst2_need_jump),
		.store(inst2_analyze_store),
		.ras_we(ras_inst2_we),
		.ras_re(ras_inst2_re),
		.ras_addr(ras_addr)
    );

	always_ff @(posedge cpu_clk)begin
		inst_buffer_index1 <= next_index1;
		inst_buffer_index2 <= !next_inst1_en ? next_index1 : next_index2;
		if(cpu_rst_n == 1'b0)begin
			accept_btb <= 1'b0;
			accept_btb_delay <= 1'b0;
		end
		else begin
			if(inst_accept)begin
				accept_btb <= btb_en;
				accept_btb_delay <= btb_delay & btb_en;
			end			
		end
		if(cpu_rst_n == 1'b0 || clear || next_front_clear)begin
			delay_clear <= 1'b0;
			delay_index <= 0;
			delay_branch <= 0;
			delay_addr_predict <= 0;
			delay_addr_normal <= 0;
			front_clear_accept <= 1'b0;
			clear_index <= 0;
			clear_accept_addr <= 0;
			clear_discard1 <= 0;
			clear_discard2 <= 0;
			inst_btb <= 0;
			delay_analyze_result <= 0;
			delay_addr <= 0;
		end
		else begin

			if(next_inst1_en | next_inst2_en)begin
				inst_btb <= accept_btb;
			end

			if(inst1_en && !ds_en && !front_clear_accept && (analyze_result1[1] | analyze_result1[0])
			|| !ds_en && inst2_en && !front_clear_accept && (analyze_result2[1] | analyze_result2[0]))begin
				delay_clear <= 1'b1;
			end
			else if(delay_accept)begin
				delay_clear <= 1'b0;
			end
			if(delay_clear & inst1_en & inst2_en_in  & (delay_analyze_result[1] & delay_analyze_result[0] | delay_analyze_result[1] & ~delay_analyze_result[0] & ~inst_btb | ~delay_analyze_result[1] & delay_analyze_result[0] & delay_branch & ~inst_btb))begin
				clear_discard1 <= 1'b1;
			end

			if(inst1_en && !ds_en && !front_clear_accept && (analyze_result1[1] | analyze_result1[0]))begin
				delay_index <= inst_buffer_index1 + 1;
				delay_branch <= predict_branch;
				delay_addr <= analyze_result1[1] | ~analyze_result1[1] & analyze_result1[0] & predict_branch ? analyze_addr1 : inst1_addr8;
				delay_analyze_result <= analyze_result1;
			end
			if(!ds_en && inst2_en && !front_clear_accept && (analyze_result2[1] | analyze_result2[0]))begin
				delay_index <= inst_buffer_index2 + 1;
				delay_branch <= predict_branch;
				delay_addr <= analyze_result2[1] | ~analyze_result2[1] & analyze_result2[0] & predict_branch ? analyze_addr2 : inst2_addr8;
				delay_analyze_result <= analyze_result2;
			end
			if(!front_clear_accept & front_clear_availiable)begin
				front_clear_accept <= 1'b1;
				clear_index <= delay_clear ? delay_index + 1 : ds_index + 1;
				clear_accept_addr <= delay_clear ? delay_addr : inst1_choose ? predict_addr1 : predict_addr2;
			end
		end
	end

	assign correct = buffer_tail_data.branch == buffer_tail_data.real_branch;
	assign random_u = {~u[3], ~u[2], ~u[1], ~u[0]} & {random[4], random[5], random[6], random[7]};
	assign update_use = buffer_tail_data.provider_branch != buffer_tail_data.alt_branch;
	RanGen random_gen(cpu_rst_n, 8'b01000111, cpu_clk, random);

	always_comb begin
		if(retire_en1 || retire_en2)begin
			if(!correct)begin
				case(buffer_tail_data.provider)
				T0:begin
					if(&u)begin
						dec_uses = 4'b1111;
						allocs = 4'b0;
					end
					else begin
						dec_uses = 4'b0000;
						if(random_u[0])begin
							allocs = T1;
						end
						else if(random_u[1])begin
							allocs = T2;
						end
						else if(random_u[2])begin
							allocs = T3;
						end
						else begin
							allocs = T4;
						end
					end
				end
				T1:begin
					if(u[1] & u[2] & u[3])begin
						dec_uses = 4'b1110;
						allocs = 4'b0;
					end
					else begin
						dec_uses = 4'b0;
						if(random_u[1])begin
							allocs = T2;
						end
						else if(random_u[2])begin
							allocs = T3;
						end
						else begin
							allocs = T4;
						end
					end
				end
				T2:begin
					if(u[2] & u[3])begin
						dec_uses = 4'b1100;
						allocs = 4'b0;
					end
					else begin
						dec_uses = 4'b0;
						if(random_u[2])begin
							allocs = T3;
						end
						else begin
							allocs = T4;
						end
					end
				end
				T3:begin
					if(u[3])begin
						dec_uses = 4'b1000;
						allocs = 4'b0;
					end
					else begin
						dec_uses = 4'b0;
						allocs = T4;
					end
				end
				default:begin
					dec_uses = 4'b0;
					allocs = 4'b0;
				end
				endcase
			end
			else begin
				dec_uses = 4'b0;
				allocs = 4'b0;
			end
		end
		else begin
			dec_uses = 4'b0;
			allocs = 4'b0;
		end
	end

	// assign store_info.en = 1'b1;
	// assign store_info._type = inst1_store ? analyze_result1 == 2'b11 : analyze_result2 == 2'b11;
	// assign store_info.predict_addr = inst1_store ? analyze_addr1 : analyze_addr2;
	// assign store_info.normal_addr = inst1_store ? inst1_addr8 : inst2_addr8;
	// assign store_info.branch = predict_branch;
	// assign store_info.provider_branch = prediction;
	// assign store_info.alt_branch = alt_predict_branch;
	// assign store_info.provider = providers;
	// assign store_info.index[0] = target_addr[INDEX_SIZE+1: 2];
	// assign store_info.index_ready = 0;
	// assign store_info.ght_index = next_hash_index3;
	// assign store_info.predict_exc = inst1_store ? analyze_addr1[1: 0] != 2'b00 : analyze_addr2[1: 0] != 2'b00;
	// assign store_info.btb_index = inst1_store ? inst1_addr4[8: 3] ^ inst1_addr4[14: 9] ^ inst1_addr4[20: 15] ^ inst1_addr4[26: 21] : inst2_addr4[8: 3] ^ inst2_addr4[14: 9] ^ inst2_addr4[20: 15] ^ inst2_addr4[26: 21];
	// assign store_info.btb_tag = inst1_store ? inst1_addr4[31: 2] : inst2_addr4[31: 2];
	// assign store_info.btb_delay = inst1_store ? inst1_addr[2] : inst2_addr[2];
	// assign store_info.real_addr = 0;
	// assign store_info.real_branch = 0;
	// generate;
	// 	for(genvar i=0; i<4; i++)begin
	// 		assign store_info.index[i+1] = hash_indexs[i];
	// 		assign store_info.tag[i] = hash_tags[i];
	// 	end		
	// endgenerate


	always_ff @(posedge cpu_clk)begin
		if(cpu_rst_n == `RST_ENABLE)begin
			ghr <= 0;
			alt_ctr <= 0;
			ght_ctr <= 0;
			correct_ctr <= 0;
		end
		else if(retire_en1 || retire_en2)begin
			ghr <= (ghr << 1) | buffer_tail_data.real_branch;
			if(buffer_tail_data.provider_branch != buffer_tail_data.alt_branch)begin
				if ((buffer_tail_data.alt_branch == buffer_tail_data.real_branch) && (alt_ctr != 4'b1111))begin
					alt_ctr <= alt_ctr + 1;
				end
				else if ((buffer_tail_data.alt_branch != buffer_tail_data.real_branch) && alt_ctr != 4'b0)begin
					alt_ctr <= alt_ctr - 1;
				end
			end
		end
		if(cpu_rst_n == `RST_ENABLE || clear)begin
			for(int i=0; i<INST_BUFFER_SIZE; i++)begin
				inst_buffer[i] <= 0;
			end
			buffer_head <= 0;
			buffer_tail <= 0;
			buffer_remain_count <= INST_BUFFER_SIZE;
			rob_tail <= 0;			
		end
		else begin
			buffer_remain_count <= buffer_remain_count - (!(!next_front_clear & front_clear_accept) ? add_num : 0) + (retire_en1 | retire_en2);
			buffer_tail <= buffer_tail + (retire_en1 | retire_en2);
			if(!(!next_front_clear & front_clear_accept))begin
				buffer_head <= buffer_head + add_num;
				if(inst1_store)begin
					inst_buffer[head_index].en <= 1'b1;
					inst_buffer[head_index]._type <= analyze_result1== 2'b11;
					inst_buffer[head_index].predict_addr <= analyze_addr1;
					inst_buffer[head_index].normal_addr <= inst1_addr8;
					inst_buffer[head_index].branch <= predict_branch;
					inst_buffer[head_index].provider_branch <= prediction;
					inst_buffer[head_index].alt_branch <= alt_predict_branch;
					// inst_buffer[head_index].ght_branch <= ght_branch;
					// inst_buffer[head_index].uncorrect_branch <= uncorrect_branch;
					inst_buffer[head_index].provider <= providers;
					inst_buffer[head_index].index[0] <= target_addr[INDEX_SIZE+1: 2];
					inst_buffer[head_index].index_ready <= 1'b0;
					inst_buffer[head_index].ght_index <= next_hash_index3;
					inst_buffer[head_index].predict_exc <= analyze_addr1[1: 0] != 2'b00;
					inst_buffer[head_index].btb_index <= inst1_addr4[8: 3] ^ inst1_addr4[14: 9] ^ inst1_addr4[20: 15] ^ inst1_addr4[26: 21];
					inst_buffer[head_index].btb_tag <= inst1_addr4[31: 2];
					inst_buffer[head_index].btb_delay <= inst1_addr[2];
					for(int i=0; i<4; i++)begin
						inst_buffer[head_index].index[i+1] <= hash_indexs[i];
						inst_buffer[head_index].tag[i] <= hash_tags[i];
					end
				end
				else if(inst2_store)begin
					inst_buffer[head_index].en <= 1'b1;
					inst_buffer[head_index]._type <= analyze_result2 == 2'b11;
					inst_buffer[head_index].predict_addr <= analyze_addr2;
					inst_buffer[head_index].normal_addr <= inst2_addr8;
					inst_buffer[head_index].branch <= predict_branch;
					inst_buffer[head_index].provider_branch <= prediction;
					inst_buffer[head_index].alt_branch <= alt_predict_branch;
					// inst_buffer[head_index].ght_branch <= ght_branch;
					// inst_buffer[head_index].uncorrect_branch <= uncorrect_branch;
					inst_buffer[head_index].provider <= providers;
					inst_buffer[head_index].index[0] <= target_addr[INDEX_SIZE+1: 2] ;
					inst_buffer[head_index].index_ready <= 1'b0;
					inst_buffer[head_index].ght_index <= next_hash_index3;
					inst_buffer[head_index].predict_exc <= analyze_addr2[1: 0] != 2'b00;
					inst_buffer[head_index].btb_index <= inst2_addr4[8: 3] ^ inst2_addr4[14: 9] ^ inst2_addr4[20: 15] ^ inst2_addr4[26: 21];
					inst_buffer[head_index].btb_tag <= inst2_addr4[31: 2];
					inst_buffer[head_index].btb_delay <= inst2_addr[2];
					for(int i=0; i<4; i++)begin
						inst_buffer[head_index].index[i+1] <= hash_indexs[i];
						inst_buffer[head_index].tag[i] <= hash_tags[i];
					end
				end
			end
			if(wb_hit1)begin
				inst_buffer[wb_branch_index1].real_branch <= wb_branch1[0];
				inst_buffer[wb_branch_index1].real_addr <= wb_branch1;
			end
			if(wb_hit2)begin
				inst_buffer[wb_branch_index2].real_branch <= wb_branch2[0];
				inst_buffer[wb_branch_index2].real_addr <= wb_branch2;
			end

			rob_tail <= rob_tail + ((dis_en1 | dis_en2));

			if(dis_en1 | dis_en2)begin
				inst_buffer[rob_tail].index_ready <= 1'b1;
			end

			if(retire_en1 || retire_en2)begin
				inst_buffer[buffer_tail].en <= 1'b0;
			end
		end
	end
endmodule